<?php
/**
 * Created by PhpStorm.
 * User: ford
 * Date: 14-10-30
 * Time: 下午2:29
 */

/*********************************************
 *********** 下面是异常的示例 ******************/
class Conf
{
	private $file;
	private $xml;

	function __construct($file)
	{
		$this->file = $file;
		if(!file_exists($file))
			throw new Exception("File '$file' does not exist!");
		$this->xml = simplexml_load_file($file);
	}

	function test()
	{

	}
}
try
{
	$conf = new Conf(dirname(__FILE__)."/standard.html");
}
catch(Exception $e)
{
	die($e);	//由于Exception定义了__toString()方法，所以此处等价于	die($e->__toString());
}
/************* 异常处理示例结束 ***************
 *******************************************/
?>
<!DOCTYPE html>
<html>
<head>
	<title>深入PHP面向对象、模式与实践（第3版）</title>
	<base url="http://localhost/notebook" />
	<meta name="Author" content="Ford" />
	<meta name="Description" content="A Sample example" />
	<meta charset="utf-8" />
	<link type="text/css" rel="stylesheet" href="css/zui.css" />
</head>
<body>
<article>
	<header><h1>译者序</h1></header>
	<section>
		<p>PHP的学习路线：PHP基础入门（语法、常用函数和扩展等）->面向对象的PHP->网站软件架构设计（设计模式、框架等）->网站物理层次架构设计（分布式计算、存储、负载均衡、可高用性等 ）。</p>
	</section>
</article>
<article>
	<header>
		<h1>第1章 PHP：设计与管理</h1>
	</header>
	<section>
		<p>eXtreme Programming 极限编程（简称XP）：灵活的，面向对象设计的，高度集中的计划和执行方法。主张自动化的、经常进行的测试是项目成功的关键，而且测试方法最好是在目标代码编写前就设计好的。项止应该被 分为小的迭代任务。要一直仔细检查代码和需求，架构和设计是其离和不变的版本，代码可以频繁修改。</p>
	</section>
	<footer>
		<p>这是一本关于面向对象设计与编程的书，也介绍了管理PHP代码库（从协作开发到部署）的工具。</p>
	</footer>
</article>
<article>
	<header>
		<h1>第2章 PHP与对象</h1>
	</header>
	<section>
		<p>从PHP5开始，明确支持对向和面向对象程序设计。虽然有些时候让代码快速建立并执行比搭建一个良好的易于扩展的架构更为重要，但大部分应以后者为重。</p>
	</section>
	<footer>
		<p>这一章讲了PHP的发展和引入OOP的过程。注意，PHP4中对象变量的赋值与其它OOP语言不同，不是以引用传递而是值传递。本书是以PHP5.3为基础的，引入了命名空间。</p>
	</footer>
</article>
<article>
	<header>
		<h1>第3章 对象基础</h1>
	</header>
	<section>
		<p>除非在类中定义了__toString()方法，否则在5.3中不再支持用var_dump()函数来打印对象内容。PHP5中引入了定义对象变量使用范围的三个关键字：public/private/protected，之前版本所有的var关键字，在PHP5中被视为public。一般而方言，属性要设置为private，方法要设置为public，如果只在类中使用且不想被其他程序访问的函数，也应设置为private。</p>
		<p>PHP没有强制属性都在类中声明，因此，可以动态地增加属性到对象，比如:$person->newAddition = "A sample";。当然，不要使用这种方法，但是正因如此，如果属性名输错时，PHP并不会报错，而是视为创建了一个新的属性。</p>
		<p>PHP5的构造方法改名为__construct()，而不是和以前一样使用类的同名方法，当然，以前的方法仍然有效。在面向对象开发中，专注特定任务，忽略外界上下文是一个重要的设计原则。要始终考虑如何在方法中处理无效的输入。参数也可以是对象变量。</p>
		<p>尝试数据与数据管理分离。可在函数或方法的参数表中使用自定义参数类型（即类名），这样在调用时就可以进行参数类型自动检测了，数组参数也有类似功能，但是基本类型做不到，只能添加判断代码加以识别。</p>
		<p>创建继承树的第一步是找到现有基类元素中不适合放在一起，或者不需要进行特殊处理的类方法。子类默认继承父类的public和protected方法，如果子类没有定义构造方法，将自动调用父类的构造方法。最好将类的属性范围都设为private或protected，在需要的时候再放松。</p>
	</section>
	<footer>
		<p>这一章讲了类的基本定义和继承的技巧。注意，父类的私有属性，竟然也可以在子类中通过构造函数（因为构造函数是public的）来初始化，并通过父类的公有访问方法来访问。</p>
	</footer>
</article>
<article>
	<header>
		<h1>第4章 高级特性</h1>
	</header>
	<section>
		<p>static静态的方法和属性是以类为作用域的，不需要将类实例化就可以通过类名来访问，要在当前类中的定义中使用自己的静态方法的话，用self::来调用，因为它不属于某个实例，因此，不能在此处也不能在静态方法中使用$this。</p>
		<p>因为类的每个实例都可以访问类的静态属性，所以常用它来设置值。一些常用的简单功能可以定义为静态方法，这样可避免实例化一个类。对于那些没有访问类中属性的方法也可以设置为静态的，比数对数据库的访问之类的方法。</p>
		<p>类常量以const来定义，名称不需要用$引用，而且要用大写，类常量只能用基本数据类型的值。</p>
		<p>抽象类至少包含一个抽象方法，用abstract声明。抽象类的子类必须实现父类中所有的抽象方法，或者把它们也声明为抽象方法，那么这个子类又是一个抽象类，抽象类中的抽象方法只需如此声明：abstract function noBody();，注意，后面没有函数内容的大括号，空的也不行。</p>
		<p>接口interface，就是纯粹的模块，只定义，不实现，一个类可以用implements引入多个接口，只需如下定义：class Sample extends Parents implements Interface1, Interface2, ...。它的好处是让一个类同时拥有多个父类。</p>
		<p>看下面的类定义：</p>
		<pre>
			abstract class DomainObject
			{
				public static function create()
				{
					return new static();
				}
			}

			class User extends DomainObject
			{
			}

			class Document extends DomainObject
			{
			}
		</pre>
		<p>static在上面的例子中作用类似于self，但是，它指的是被调用的类，而不是定义它的类。在这个例子中，执行User::create()方法将返回一个User对象，Document::create()将返回一个Document对象。和self与parent一样，它还可以作为方法调用的标识符，比如：$this->group = static::getGroup();可以这样来调用定义的静态方法，作用和上面的示例一样，指的是被调用的类中的方法，而不是包含它的定义的父类中的方法。</p>
		<p>通常我们希望封装好的类是完整和独立的，不需要从外部干预代码的执行。因此，要把错误处理的责任放在类的内部，而不能依赖外部代码。PHP5使用Exception类型的对象来存放和报告错误信息，它有两个可选的初始化参数：消息字符串和错误代码。Exception类的方法列表：</p>
		<table class="class-table table-bordered">
			<thead>
				<tr><th>方法</th><th>描述</th></tr>
			</thead>
			<tbody>
				<tr><td>getMessage()</td><td>获得传递给构造方法的消息字符串</td></tr>
				<tr><td>getCode()</td><td>获得传递给构造方法的错误代码</td></tr>
				<tr><td>getFile()</td><td>获得产生异常的文件</td></tr>
				<tr><td>getLine()</td><td>获得生成异常的行号</td></tr>
				<tr><td>getPrevious()</td><td>获得一个嵌套的异常对象</td></tr>
				<tr><td>getTrace()<i>重要</i></td><td>获得一个多维数组，这个数组追踪导致异常的方法调用，包含方法、类、文件和参数数据</td></tr>
				<tr><td>getTraceAsString<i>重要</i></td><td>获得getTrace()返回数据的字符串版本</td></tr>
				<tr><td>__toString()</td><td>在字符串中使用Exception对象时自动调用。返回一个描述异常细节的字符串</td></tr>
			</tbody>
		</table>
		<p>可以联合使用throw关键字和Exception对象来抛出异常，并停止执行当前方法，取代使用die来强行终止的方法。比如：</p>
		<pre>
			class Conf
			{
				__construct()
				{
					if(!file_exists($file))
						throw new Exception("File '$file' does no exist!");
				}
			}
		</pre>
		<p>如上定义，将可能会抛出异常的语句放入try子句中执行，随后接catch子句就可以在发生异常时，将控制权从try子句移交给catch子句实现异常处理了，比如，接上例：</p>
		<pre>
			try
			{
				$conf = new Conf(dirname(__FILE__)."/conf01.xml";
				print "user:".$conf->get('user')."\n";
				.....
				$conf->write();
			}
			catch(Exception $e)
			{
				die($e->toString);
			}
		</pre>
		<p>可以通过继承Exception类来实现自定义异常处理，只需要用throw一个自定义的Exception类即可，相应的也要有接收自定义Exception类的catch语句，而且，catch语句中也可以再次使用throw抛出Exception对象。当异常没有被客户端代码捕获时，会被再次抛出，客户的调用代码会优先捕获它，这样的过程会一再发生，直接异常被捕获或不再抛出，如果异常到最后也没有被捕获，将会引发致命错误。</p>
		<p>使用final定义类，可以禁止类被继承，如果仅使用final定义类中的方法，类中的方法不可被子类改写。这不符和类的设计原则，应慎用。</p>
		<p>PHP5内置了五个拦截器方法。即在条件满足时自动执行，之所以说是不确定的属性，因为它接收的参数名称为属性名，如下：</p>
		<ul>
			<li>__get($property)-访问未定义或私有的属性时被调用</li>
			<li>__set($property, $value)-给未定义或私有的属性赋值时被调用</li>
			<li>__isset($property)-对未定义或私有的的属性使用isset()函数查看属性是否存在时时被调用</li>
			<li>__unset($property)-对未定义或私有的属性调用unset()时被调用</li>
			<li>__call($method, $arg__array)-调用未定义或私有的方法时被调用</li>
		</ul>
		<p>__get()方法会在对象的属性被访问时调用，即使类的属性设置为private，只要__get()方法定义了此属性的访问方式，也是可以直接通过对象变量的访问符->来访问类的private属性的。比如：</p>
		<pre>
			class Person
			{
				private $name;	//这是一个私有属性

				function __construct($name)
				{
					$this->name = $name;
				}

				function __get($property)
				{
					$method = "get{$property}";		//因为PHP不区分大小写，所以，可以这样来识别函数
					if(method_exists($this, $method))
					{
						return $this->$method();	//注意，这里的属性是个变量，指代函数名称
					}
				}

				function __set($property, $name)
				{
					if($property == 'name')
						$this->name = $name;
				}

				function getNamE()		//注意，PHP函数名不区分大小写，因此上面的__get()方法中对函数的调用是正确的
				{
					return $this->name;
				}

				function __isset($property) 	//注意此函数的返回值，这样设计的好处假定所有属性都为private，都是通过自定义函数访问。如果不存在，则返回null
				{
					$method = "get{$property}";
					return {method_exists($this, $method);
				}
			}

			$person = new Person("Ford");
			print $person->name;	//__get()方法自动执行
			$person->name = "Zhang ";	//__set()方法自动执行

			print $person->name;
		</pre>
		<p>PHP的析构方法是__distruct()，可用于处理数据保存的工作，当对一个对象调用unset()函数时，或进程中不再引用某个对象时，它就被溜须毁了。不过，不要经常用这类方法执行它该该做析构以外的事，将保存的方法写在它该呆的地方，在析构时检查是否已保存是可以的。</p>
		<p>PHP5.3以后，对象变量赋值与其它语言一样，采用引用传递。即两个变量指向同一个对象的引用。如果要得到一个对象的拷贝，需要使用clone关键字，这时会调用类中的__clone()方法，根据方法定义生成一个全新的对象副本。注意：__clone()方法中只需要将不能直接复制的变量赋值重新定义即可，没有重新定义的基本数据类型属性的值将自动复制。如果类包含有自定义数据类型的属性，就需要在__clone()方法中再次用clone关键字对此属性赋值。另，__clone()方法是在复制得到的对象上运行的，而不是在原始对象上运行。</p>
		<p>受Java启发，PHP5.3引入了__toString()方法，打印输出对象内容，它将在对对象执行print或echo时自动执行。</p>
		<pre>
		class Product
		{
			public $name;
			public $price;

			function __construct($name, $price)
			{
				$this->name = $name;
				$this->price = $price;
			}
		}

		class ProcessSale
		{
			private $callbacks;

			function registerCallback($callback)
			{
				if(!is_callable($callback))
				{
					throw new Exception("callback not callable");
				}
				$this->callbacks[] = $callback;
			}

			function sale(Product $product)
			{
				print "{$product->name}: processing \n";
				foreach($this->callbacks as $callback)
				{
					call_user_func($callback, $product);
				}
			}
		}
		</pre>
	</section>
	<footer>
		<p>这一章后面说的回调和匿名函数没太理解。回头再看。</p>
	</footer>
</article>
<article>
	<header>
		<h1>第5章 对象工具</h1>
	</header>
	<section>
		<p>PHP现在还没有package的概念，但是自5.3版本以来引入了命名空间。为了避免类和变量的名称重复，使用命名空间作为容器，将类、函数和变量放在其中，在命名空间中可以无条件地访问这些项，而在命名空间之外，必须导入或引用命名空间才能访问它所包含的项。</p>
		<p>定义命令空间使用namespace关键字，它必须在文件的第一条语句。PHP支持嵌套的命名空间，只需用\将每层分开即可，命名技巧参照Java包命名，比如：</p>
		<pre>namespace com\getinstance\util</pre>
		<p>使用use关键字引入其它命名空间。在PHP代码中可以这样添加系统包含路径：</p>
		<pre>
			set_include_path(get_include_path()."/home/ford/my_php_lib/");		//注意目录结尾处的斜线
		</pre>
       <p>下面是一段查找类的代码，可用于__autoload()函数中：</p>
		<pre>
			$class_name = "Task";		//这儿可以替换为__autoload()函数的参数名

			$path = "tasks/{$class_name}.php";
			if(!file_exists($path))
			{
				throw new Exception("No such file as {$path}!");
			}

			require_once($path);
			$q_class_name = "tasks/$class_name";	//方便起间，以类名命名定义它的PHP文件，直接用$class_name代替即可
			if(!class_exists($q_class_name);	//class_exists()函数，用于判断类是否存在，这段代码的意义在于更为安全一些
			{
				throw new Exception("No such class as $q_class_name");
			}
			$my_obj = new $q_class_name();
		</pre>
		<p>get_class()函数可以检查对象所属的类，并以字符串形式返回类名称，还可以用instanceof关键字来判断对象是否属于某个类。get_class_methods()函数可以得到一个类中所有的方法列表（不包括私有方法），而get_class_vars()函数则可以取得类的属性列表，以数组形式返回。它的参数是类名的字符串，比如：</p>
		<pre>print_r(get_class_methods('Conf'));</pre>
		<p>get_parent_class()函数可以取得一个类的父类名称，如果不存在就返回false。有两个函数可以动态调用方法：call_user_func()和call_user_func_array()。这一段计得还可以，但是估计在目前的编程中还用不到，也许应当改变一下方式了。</p>
		<p>PHP提供了反射API，利用反射API提供的这些类可以在运行时访问对象、函数和脚本中的扩展的信息。这是不中缺少的类测试工具。下面是反射API的部分类：</p>
		<table class="table table-bordered">
			<thead>
				<tr>
					<th>类名</th>
					<th>描述</th>
					<th>示例</th>
				</tr>
			</thead>
			<tbody>
				<tr>
					<td>Reflection</td>
					<td>为类的摘要信息提供静态函数export()</td>
					<td>$prod_class = new ReflectionClass('Produce');<br />Reflection::export($prod_class);</td>
				</tr>
				<tr>
					<td>ReflectionClass</td>
					<td>类信息和工具</td>
					<td>见上一行的示例，需要先创建这个类的对象才能用Reflection的静态方法格式化输出</td>
				</tr>
				<tr>
					<td>ReflectionMethod</td>
					<td>类方法信息和工具</td>
					<td></td>
				</tr>
				<tr>
					<td>ReflectionParameter</td>
					<td>方法参数信息</td>
					<td></td>
				</tr>
				<tr>
					<td>ReflectionProperty</td>
					<td>类属性信息</td>
					<td></td>
				</tr>
				<tr>
					<td>ReflectionFunction</td>
					<td>函数信息和工具</td>
					<td></td>
				</tr>
				<tr>
					<td>ReflectionExtension</td>
					<td>PHP扩展信息</td>
					<td></td>
				</tr>
				<tr>
					<td>ReflectionException</td>
					<td>错误表</td>
					<td></td>
				</tr>
			</tbody>
		</table>
		<p>如果要检查类的属性只需如下两步：</p>
		<pre>
			$prod_class = new ReflectionClass('CdProduct');		//用类名来创建一个新的ReflectionClass对象
			Reflection::export($prod_class);		//用Reflection类的静态方法打印类的详细情况。
		</pre>
		<p>var_dump()和print_r()函数是检测PHP代码中数据的利器，但是对于类说和函数，反身API提供了更高层次的功能。还可以象下面这样定义一个函数，用于对类的检测：</p>
		<pre>
			function classData(ReflectionClass $class)
			{
				$details = "":
				$name = $class->getName();		//这是ReflectionClass内定义的方法

				if($class->isUserDefined())
					$details .= "$name is user defined\n";
				if($class->isInternal())
					$details .= "$name is built-in\n";
				if($class->isAbstract())
					$details .= "$name is a abstract class\n";
				if($class->isFinal())
					$details .= "$name is a final class\n";
				if($class->isInstantiable())		//检测类是否可实例化
					$detail .= "$name can be instantiated\n";
				else
					$detail .= "$name can not be instantiated\n";

				return $details;
			}
		</pre>
		<p>还可以利用ReflectionClass类来获取源代码，自定义类如下：</p>
		<pre>
			class ReflectionUtil
			{
				static function getClassSource(ReflectionClass $class)
				{
					$path = $class->getFileName();		//得到类文件的绝对路径
					$lines = @file($path);
					$from = $class->getStartLine();
					$to = $class->getEndLine();
					$len = $to - $from + 1;

					return implode(array_slice($lines, $from - 1, $len);
				}
			}
		</pre>
		<p>ReflectionMethod对象可用于检查类中的方法，当然前提也是要先得到一个ReflectionMethod对象，有两种方式：
			<ul>
				<li>从ReflectionClass::getMethods()获得ReflectionMethod对象数组</li>
				<li>从ReflectionClass::getMethod()方法，获得指定方法名的ReflectionMethod对象</li>
			</ul>
		ReflectionClass一样，也可以用类似的方法获得方法的源代码，只需将上面定义的getClassSource方法参数改为ReflectionMethod类型即可。
		</p>
		<p>ReflectionParameter类可以用来检查方法参数，要获得ReflectionParameter对象需要使用ReflectionMethod::getParameters()方法，它返回一个参数数组。</p>
	</section>
	<footer>
		<p>反射API也许会用到吧，在模块化编程的时候用于动态加入模块。这个示例不完整，回头再看。</p>
	</footer>
</article>
<article>
	<header>
		<h1>第6章 对象与设计</h1>
	</header>
	<section>
		<p>从底层上看，设计是定义系统组成并组织各组件间关系的过程，也就是类和对象规划和定义的过程。理想情况下，各组件都应该职责清晰、分工明确，不要让代码间的关联范围太广。将职责相关的组件紧紧结合在一起而与外部系统环境隔开称为正交。正交主张不需要任何特殊配置就能把一个组件插入到新系统中，这样代码最维护也最安全。</p>
		<p>定义类的最好方式：让一个类只有一个主要职责，并且任务要尽可能独立，在描述类的作用时如果要用并且或是或者之类的字样那可能就要分成多个类了，如果描述太复杂，也应该将其分拆为几个类。但是，设计原则并不能帮你分析问题，特殊情况特殊对待，不要拘泥不化。</p>
		<p>如果代码中存在多个条件语句，说明需要使用多态，即由一个公用接口后面维护多个实现。多态并没有消息if语句，只是使条件代码更为集中。由于PHP不限定函数的返回值类型，因此，尽量要在代码注释中说明。</p>
		<p>封装，使系统中的每一部分尽可能独立。为接口而不是实现而编程，在设计初期，仅需要搭建框架，不要考虑细节，细节可在实现框架后让代码中的结构和关系引导你去实现。</p>
		<p>如果在写代码的时候总是感觉似曾相识，那代码可能重复了；查看重复的地方，它们本应该放在一起；从一个方法传递变量到另一个方法可能会产生问题，可以考虚使用全局变量𦍓少麻烦；如果一个类一次完成很多工作就需要检查类的职责列表了，可以将其中一些功能提取出来成为一个基类；条件语句如果太多，看看是不是有必要拆分。</p>
		<p>类图可以清晰地描述结构和模式，通过类图可以清楚年出结构和模式的意图，类图是UML的一部分。当一个类的属性保存了另一个类的一个或多个实例的引用时，两个类就产生了关联。如果类A里有类B的实例，则用指向类B的单箭头表示其关联，两个类互相关联就用双向箭头连接。</p>
		<p>时序图是基于对象而不是基于类的，它用于为系统中过程化的行为建模，它是为过程建模，将动态的交互操作清晰地展现。</p>
	</section>
	<footer>
		<p>这一章介绍了面向对象的设计理念产，以及UML（Unified Modeling Language）统一建模语言的基础知识。</p>
	</footer>
</article>
<article>
	<header>
		<h1>第7章 设计模式</h1>
	</header>
	<section>
		<p>设计模式就是分析过的问题和问题的解决方案的实践方式，即可以被重复使用的解决方案，或者说它是一种可供借鉴的解决问题的经验总结。</p>
		<p>一个设计模式的核心由四部分组成：命名、问题、解决方案和效果。</p>
		<p>现在暂切理解设计模式为软件开发文档的一种，主要由以下这些部分组成</p>
		<ul>
			<li>意图：简要概括目的</li>
			<li>适用范围：适用于哪些情况，表明其价值</li>
			<li>结构/交互：可能包含UML图和交互图，用于描述解决方案中类和对象之间的关系</li>
			<li>实现：着眼于解决方案的细节，介绍应用解决方案时可能发生的问题，提供部署技巧</li>
			<li>示例代码：示例代码可以用任何一种面向对象语言编写</li>
			<li>已知应用：使用此模式的真实系统，一般不能少于3个，至少用过3次才可称为一个模式</li>
			<li>相关模式：可能存在的模式间的合作</li>
		</ul>
	</section>
	<footer>
		<p>这一章说了半天听看明白设计模式是个什么东东，也许是翻的名词不对。</p>
	</footer>
</article>
<article>
	<header>
		<h1>第8章 模式原则</h1>
	</header>
	<section>
		<p>不要把类设计的太复杂，功能要简单，需要多个功能只需组合就行了，组合优于继承，因为继承会限制灵活性。</p>
	</section>
	<footer>
		<p>这一章讲了设计模式的原则，还是一样不清楚。一句话，合理地定义类，利用组合和继承等关系搭建一个高内聚低耦合和系统。</p>
	</footer>
</article>
<article>
	<header>
		<h1>第9章 生成对象</h1>
	</header>
	<section>
		<p>针对接口编程的一直缺点就是对象的实例化被推迟。全局变量是面向对象程序员遇到的引发bug的主要原因之一。因为全局变量将类捆绑于特定的环境 ，破坏了封装。面向对象设计强调“抽象类高于实现”，也就是说要尽量一般化而不是特殊化。工厂方法模式把创建者类与要生产的产品类分离开来，创建者是一个工厂类，其中定义了用于生成产品对象（通过返回对象变量实现）的方法。</p>
		<p>抽象工厂模式</p>
		<ul>
			<li>首先，将系统与实现的细节分离，这样就可以在示例中添加或移动任意数目的编码格式而不会影响系统</li>
			<li>对系统中功能相关的元素强制进行组合</li>
			<li>添加新产品的话，会有点麻烦，因为必须修改抽象创建者和它的每一个具体实现</li>
		</ul>
		<p></p>
	</section>
	<footer>
		<p></p>
	</footer>
</article>
<article>
	<header>
		<h1>第10章 让面向对象编程更加灵活的模式</h1>
	</header>
	<section>
	</section>
	<footer>
		<p></p>
	</footer>
</article>
<article>
	<header>
		<h1>第11章 执行及描述任务</h1>
	</header>
	<section>
	</section>
	<footer>
		<p></p>
	</footer>
</article>
<article>
	<header>
		<h1>第12章 企业模式</h1>
	</header>
	<section>
	</section>
	<footer>
		<p></p>
	</footer>
</article>
<article>
	<header>
		<h1>第13章 数据库模式</h1>
	</header>
	<section>
	</section>
	<footer>
		<p></p>
	</footer>
</article>
<article>
	<header>
		<h1>第14章 良好与糟糕的实践</h1>
	</header>
	<section>
	</section>
	<footer>
		<p></p>
	</footer>
</article>
<article>
	<header>
		<h1>第15章 PEAR和Pyrus</h1>
	</header>
	<section>
	</section>
	<footer>
		<p></p>
	</footer>
</article>
<article>
	<header>
		<h1>第16章 用phpDocumentor生成文档</h1>
	</header>
	<section>
	</section>
	<footer>
		<p></p>
	</footer>
</article>
<article>
	<header>
		<h1>第17章 使用Subversion进行版本控制</h1>
	</header>
	<section>
	</section>
	<footer>
		<p></p>
	</footer>
</article>
<article>
	<header>
		<h1>第18章 使用PHPUnit进行测试</h1>
	</header>
	<section>
	</section>
	<footer>
		<p></p>
	</footer>
</article>
<article>
	<header>
		<h1>第19章 用Phing实现项目的自动构建</h1>
	</header>
	<section>
	</section>
	<footer>
		<p></p>
	</footer>
</article>
<article>
	<header>
		<h1>第20章 持续集成</h1>
	</header>
	<section>
	</section>
	<footer>
		<p></p>
	</footer>
</article>
</body>
</html>
<article>
	<header>
		<h1>第21章 对象、模式与实践</h1>
	</header>
	<section>
	</section>
	<footer>
		<p></p>
	</footer>
</article>
